package cn.sc.summer.gateway.swagger;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.sc.summer.constant.gateway.GatewayConstant;
import cn.sc.summer.redis.util.NacosInstancesService;
import cn.sc.summer.redis.util.RedisHelper;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@Primary
@AllArgsConstructor
@Profile({"dev-8", "dev-17"})
public class SwaggerResourceConfig implements SwaggerResourcesProvider {

    //未配置动态路由时，从yml文件中获取
/*    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;*/

    /**
     * 排除swagger捕捉的服务
     */
    public static final List<String> IGNORE_SERVER = Collections.unmodifiableList(new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("summer-auth");
        }
    });

    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    /**
     * 从网关配置文件中获取各微服务的分支
     * <br>逻辑为：微服务启动后，向redis中添加启动成功标识，此类从nacos获取动态路由进行路由服务解析，在通过微服务标识判定服务是否在线，在线且能正常访问则展现
     *
     * @return swagger路由服务列表
     */
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();

        //此处设置了网关与nacos的动态路由，swagger资源从redis中获取
        Map<Object, Object> swaggerRouting = RedisHelper.hmGet(GatewayConstant.SWAGGER_DYNAMIC_ROUTING);
        swaggerRouting.forEach((key, value) -> {
            if (NacosInstancesService.containInstance(key.toString(), nacosDiscoveryProperties)) {
                if (StrUtil.isNotBlank(value.toString())) {
                    RouteDefinition routeDefinition = JSONObject.parseObject(value.toString(), RouteDefinition.class);
                    routeDefinition.getPredicates().stream()
                            .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                            .forEach(predicateDefinition -> resources.add(swaggerResource(key.toString(), predicateDefinition.getArgs().get("pattern")
                                    .replace("**", "v2/api-docs"))));
                    log.info("-> Get the Swagger resource service: {}", key);
                }
            }
        });

        //未配置动态路由时，从yml文件中获取
/*      List<String> routes = new ArrayList<>();
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
            route.getPredicates().stream()
                    .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                    .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
                            predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                    .replace("**", "v2/api-docs"))));
        });*/
        if (CollUtil.isNotEmpty(IGNORE_SERVER)) {
            return resources.stream().filter(item -> !IGNORE_SERVER.contains(item.getName()))
                    .collect(Collectors.toList());
        }
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        log.info("==> Swagger resource acquisition : Server name: {} , Resource location: {} ", name, location);
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }

}
